#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/input.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


#define KEY_NAME	 	"mykey" 	/* 名字 */

#define KEY_NUM 		  1			/* 按键数量 */

/* 中断 IO 描述结构体 */
typedef struct IrqKey
{
	int iGpio;							 	/* gpio */
	int iIrqNum;							/* 中断号 */
	unsigned char ucKeyValue;				/* 按键对应的键值 */
	char name[10];						 	/* 名字 */
	irqreturn_t (*handler)(int, void *); 	/* 中断服务函数 */
}T_IrqKey,*PT_IrqKey;

/* imx6uirq 设备结构体 */
typedef struct KeyDevice
{
	dev_t DevID;							/* 设备号 */
	struct cdev tCharDev;					/* cdev */
	struct class *ptClass;					/* 类 */
	struct device *ptDevice;				/* 设备 */
	int iMajor;								/* 主设备号 */
	int iMinor;								/* 次设备号 */
	struct device_node *ptDeviceNode;		/* 设备节点 */
	atomic_t keyvalue;						/* 有效的按键键值 */
	atomic_t releasekey;					/* 标记是否完成一次完成的按键*/
	struct timer_list tTimer;				/* 定义一个定时器*/
	T_IrqKey tIrqKey[KEY_NUM]; 		        /* 按键描述数组 */
	unsigned char ucCurKeyNum;				/* 当前的按键号 */
    struct input_dev *ptInputDev;		    /* input结构体 */
}T_KeyDevice,*PT_KeyDevice;

T_KeyDevice g_tMyKey; 

static irqreturn_t Key0Handler(int irq, void *ptDevice)
{
	PT_KeyDevice dev = (PT_KeyDevice)ptDevice;
	dev->ucCurKeyNum = 0;
	dev->tTimer.data = (volatile long)ptDevice;
	mod_timer(&dev->tTimer, jiffies + msecs_to_jiffies(10));	/* 10ms定时 */

	return IRQ_RETVAL(IRQ_HANDLED);
}

static void TimerFunction(unsigned long arg)
{
	unsigned char ucValue;
	unsigned char ucNum;
	PT_IrqKey ptIrqKey;
	PT_KeyDevice dev = (PT_KeyDevice) arg;

	ucNum = dev->ucCurKeyNum;

	ptIrqKey = &dev->tIrqKey[ucNum];

	ucValue = gpio_get_value(ptIrqKey->iGpio); 		/* 读取IO值 */
	if (ucValue == 0)                             	/* 按下按键 */
	{
		input_report_key(dev->ptInputDev, ptIrqKey->ucKeyValue, 1);     /* 最后一个参数表示按下还是松开，1为按下，0为松开 */
		input_sync(dev->ptInputDev);
	}
	else             							 	/* 按键松开 */
	{
        input_report_key(dev->ptInputDev, ptIrqKey->ucKeyValue, 0);
		input_sync(dev->ptInputDev);
	}
}

static int KeyProbe(struct platform_device *dev)
{
    int ret;
	/*读取设备树信息*/
	/*1、获取设备树节点*/
	g_tMyKey.ptDeviceNode = of_find_node_by_path("/mykey");
	if(g_tMyKey.ptDeviceNode == NULL) {
		printk("mykey node not find!\r\n");
		return -EINVAL;
	} else {
		printk("mykey node find!\r\n");
	}
	/*2、获取GPIO*/
	g_tMyKey.tIrqKey[0].iGpio = of_get_named_gpio(g_tMyKey.ptDeviceNode, "key-gpio", 0);
	if (g_tMyKey.tIrqKey[0].iGpio < 0)
	{
		printk("can't get key-gpio");
		return -EINVAL;
	}
	printk("key-gpio%d num = %d\r\n", 0, g_tMyKey.tIrqKey[0].iGpio);

	memset(g_tMyKey.tIrqKey[0].name,0x00,sizeof(g_tMyKey.tIrqKey[0].name));
	sprintf(g_tMyKey.tIrqKey[0].name,"key0");
	g_tMyKey.tIrqKey[0].name[9] = '\0';
	/*3、设置GPIO功能*/

	gpio_request(g_tMyKey.tIrqKey[0].iGpio,g_tMyKey.tIrqKey[0].name);
	gpio_direction_input(g_tMyKey.tIrqKey[0].iGpio); 

	/*4、获得中断号，申请中断，注册中断处理函数*/

	g_tMyKey.tIrqKey[0].iIrqNum =  irq_of_parse_and_map(g_tMyKey.ptDeviceNode,0); /*解析设备树中的中断消息*/

	//g_tMyKey.tIrqKey[0].iIrqNum =  gpio_to_irq(g_tMyKey.tIrqKey[0].iGpio);        /*将指定GPIO转换为irq*/
	g_tMyKey.tIrqKey[0].handler    = Key0Handler;
	g_tMyKey.tIrqKey[0].ucKeyValue = KEY_0;

	ret = request_irq(g_tMyKey.tIrqKey[0].iIrqNum,g_tMyKey.tIrqKey[0].handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,g_tMyKey.tIrqKey[0].name,&g_tMyKey);
	if (ret < 0)
	{
		printk("irq %d request failed!\r\n",g_tMyKey.tIrqKey[0].iIrqNum);
		return -EFAULT;
	}

	/*5、定时器初始化*/

	init_timer(&g_tMyKey.tTimer);
	g_tMyKey.tTimer.function = TimerFunction;

	/*6、申请input设备*/
	g_tMyKey.ptInputDev = input_allocate_device();
	g_tMyKey.ptInputDev->name = KEY_NAME;

#if 0
	/* 初始化input_dev，设置产生哪些事件 */
	__set_bit(EV_KEY, g_tMyKey.ptInputDev->evbit);	/* 设置产生按键事件          */
	__set_bit(EV_REP, g_tMyKey.ptInputDev->evbit);	/* 重复事件，比如按下去不放开，就会一直输出信息 		 */

	/* 初始化input_dev，设置产生哪些按键 */
	__set_bit(KEY_0, g_tMyKey.ptInputDev->keybit);	
#endif

#if 0
	g_tMyKey.ptInputDev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
	g_tMyKey.ptInputDev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0);
#endif
    /*设置按键事件*/
	g_tMyKey.ptInputDev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
	input_set_capability(g_tMyKey.ptInputDev, EV_KEY, KEY_0);
    /* 注册输入设备 */
    ret = input_register_device(g_tMyKey.ptInputDev);
    if (ret)
    {
        printk("register input device failed!\r\n");
        return ret;
    }
    return 0;
}
static int KeyRemove(struct platform_device *dev)
{
    del_timer_sync(&g_tMyKey.tTimer);        /*删除timer*/

	free_irq(g_tMyKey.tIrqKey[0].iIrqNum,&g_tMyKey);

	gpio_free(g_tMyKey.tIrqKey[0].iGpio);

	/* 释放input_dev */
	input_unregister_device(g_tMyKey.ptInputDev);
	input_free_device(g_tMyKey.ptInputDev);

    return 0;
}

static struct of_device_id key_of_match[] ={
    {.compatible = "mykey"},
    {},                                         /*最后一项需为空*/
};
/*platform 驱动结构体*/
static struct platform_driver tKeyDriver = {
    .driver = {
        .name = "mykey",                 /*驱动和设备名一致时，相互匹配*/
        .of_match_table = key_of_match,       /*设备树匹配*/
    },
    .probe  =  KeyProbe,
    .remove =  KeyRemove,
};

//驱动入口函数
static int __init irqkey_init(void)
{
	return platform_driver_register(&tKeyDriver);
}
static void __exit irqkey_exit(void)
{
    platform_driver_unregister(&tKeyDriver);
}

module_exit(irqkey_exit);
module_init(irqkey_init);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Destiny");